package com.bytz.modules.cms.pay.chinapay.util;

import cn.hutool.core.exceptions.ValidateException;
import com.bytz.common.exception.BytzBootException;
import com.bytz.common.util.SpringContextUtils;
import com.chinapay.secss.SecssConstants;
import com.chinapay.secss.SecssUtil;
import io.netty.util.internal.StringUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.*;

public class AcpService {
	private static final Logger logger = LoggerFactory.getLogger(AcpService.class);

	private static SecssUtil getSecssUtil() {
		SecssUtil secssUtil = SpringContextUtils.getBean(SecssUtil.class);
		if (secssUtil == null) {
			throw new BytzBootException("没有找到Bean【SecssUtil】确认导入ChinaPayConfig");
		}

		return secssUtil;
	}

	/**
	 * @Description 获取签名
	 * @param paramMap  发送请求时携带的参数
	 **/
	public static void putSign(Map<String, Object> paramMap) {
		//签名
		SecssUtil secssUtil = getSecssUtil();
		secssUtil.sign(paramMap);
		if (!SecssConstants.SUCCESS.equals(secssUtil.getErrCode())) {
			throw new ValidateException("签名失败：" + secssUtil.getErrCode() + "=" + secssUtil.getErrMsg());
		}

		String signature = secssUtil.getSign();
		paramMap.put("Signature", signature);
	}

	public static String buildRequest(Map<String, Object> sParaTemp, String action, String strMethod) {
		//待请求参数数组
		List<String> keys = new ArrayList<>(sParaTemp.keySet());
		StringBuilder sbHtml = new StringBuilder();

		sbHtml.append("<form id=\"chinaPaySubmit\" name=\"chinaPaySubmit\" action=\"").append(action).append("\" method=\"").append(strMethod).append("\">");

		for (String key : keys) {
			Object object = sParaTemp.get(key);
			String value = "";

			if (object != null) {
				value = String.valueOf(sParaTemp.get(key));
			}

			sbHtml.append("<input type=\"hidden\" name=\"").append(key).append("\" value=\"").append(value).append("\"/>");
		}

		sbHtml.append("</form>");
		return sbHtml.toString();
	}


	/**
	 * 回调验签--验证 chinapay 返回的应答数据
	 * 参考文档Signature说明：后台返回的所有字段每个都需要通过 urldecode 进行解码后还原原始报文，
	 * 前台返回报文无需此操作
	 *
	 * @param notifyMap 支付回调的信息
	 * @return
	 */
	public static void verifyNotify(Map<String, String> notifyMap) {
		SecssUtil secssUtil = getSecssUtil();
		secssUtil.verify(notifyMap);

		if (!SecssConstants.SUCCESS.equals(secssUtil.getErrCode())) {
			throw new BytzBootException("ChinaPay返回的应答数据【验签】失败:" + secssUtil.getErrCode() + "=" + secssUtil.getErrMsg());
		}
	}

	/**
	 * @Description 接口返回参数转map
	 * @param resp      response返回参数
	 **/
	public static Map<String, String> getRespMap(String resp) {
		if (resp == null) {
			return new HashMap();
		}
		Map<String, String> resultMap = new TreeMap<>();
		String[] strS = resp.split("&", -1);

		for (String str : strS) {
			String[] keyValues = str.split("=", -1);
			if (keyValues.length < 2) {
				continue;
			}
			String key = keyValues[0];
			String value = keyValues[1];
			if (StringUtil.isNullOrEmpty(value)) {
				continue;
			}

			resultMap.put(key, value);
		}
		return resultMap;
	}

	/**
	 * 获取请求参数中所有的信息
	 * @param request
	 * @return  Map<String,String>
	 * @Date	2022年10月28日
	 *
	 */
	public static Map<String, String> getAllRequestParam(final HttpServletRequest request, String notifyType){
		Map<String, String> res = new HashMap<String, String>();
		Enumeration<?> temp = request.getParameterNames();
		if (null != temp) {
			while (temp.hasMoreElements()) {
				String en = (String) temp.nextElement();
				// 跳过空字段
				String value = request.getParameter(en);
				if (StringUtil.isNullOrEmpty(value)) {
					continue;
				}
				// 后台通知需要解码,正式使用建议前后台接收通知地址分开
				if("1".equals(notifyType)) { //后台
					//响应字段解码
					try {
						value = URLDecoder.decode(value, "UTF-8");
					} catch (UnsupportedEncodingException e) {
						throw new BytzBootException("后台通知decode失败：", e);
					}
				}
				res.put(en, value);
				//在报文上送时，如果字段的值为空，则不上送<下面的处理为在获取所有参数数据时，判断若值为空，则删除这个字段>
				//System.out.println("ServletUtil类247行  temp数据的键=="+en+"     值==="+value);
				if (null == res.get(en) || "".equals(res.get(en))) {
					res.remove(en);
				}
			}
		}
		return res;
	}


	/**
	 * 发送http请求
	 *
	 * @param requestUrl    请求地址
	 * @param params        请求参数
	 * @param requestMethod 请求方式  POST/GET
	 */
	public static String httpRequest(String requestUrl, Map<String, Object> params, String requestMethod) {
		String result = null;
		StringBuilder paramsStr = new StringBuilder();
		params.forEach((key, value) -> {
			try {
				paramsStr.append(URLEncoder.encode(key, "UTF-8")).append("=").append(URLEncoder.encode(String.valueOf(value), "UTF-8")).append("&");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		});
		if("POST".equals(requestMethod)) {

			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(30 * 1000)
					.setConnectTimeout(30 * 1000)
					.setConnectionRequestTimeout(30 * 1000)
					.build();
			HttpPost httpPost = new HttpPost(requestUrl);
			httpPost.setConfig(requestConfig);
			httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
			httpPost.setEntity(new StringEntity(paramsStr.substring(0, paramsStr.length() - 1), StandardCharsets.UTF_8));

			try (CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
				 CloseableHttpResponse response = httpclient.execute(httpPost)) {
				HttpEntity entity = response.getEntity();
				result = EntityUtils.toString(entity, "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}

		} else if("GET".equals(requestMethod)) {

			String requestUrlWithParam = requestUrl + "?" + paramsStr.substring(0, paramsStr.length() - 1);
			HttpGet httpGet = new HttpGet(requestUrlWithParam);
			try(CloseableHttpClient httpClient = HttpClients.createDefault();
				CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
				HttpEntity httpEntity = httpResponse.getEntity();
				result = EntityUtils.toString(httpEntity, "UTF-8");
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		return result;
	}


	private static RequestConfig requestConfig;
	private static PoolingHttpClientConnectionManager connMgr;

	/**
	 * 发送 SSL POST 请求（HTTPS），K-V形式
	 *
	 * @param apiUrl API接口URL
	 * @param params 参数map
	 */
	public static String doPostSSL(String apiUrl, Map<String, Object> params, Map<String, String> headers) {
		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
				.setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
		HttpPost httpPost = new HttpPost(apiUrl);
		CloseableHttpResponse response = null;
		String httpStr = null;

		try {
			List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
				pairList.add(pair);
			}
			httpPost.setEntity(new UrlEncodedFormEntity(pairList, StandardCharsets.UTF_8));
			if (headers != null) {
				for (String key : headers.keySet()) {
					httpPost.setHeader(key, headers.get(key));
				}
			}
			response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				throw new Exception("银联返回状态码：" + statusCode);
			}
			HttpEntity entity = response.getEntity();
			if (entity == null) {
				throw new Exception("银联返回结果为空");
			}
			httpStr = EntityUtils.toString(entity, "utf-8");
		} catch (Exception e) {
			throw new BytzBootException("调用查询银联支付结果接口出错：" + e.getMessage(), e);
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
				} catch (IOException e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
		return httpStr;
	}


	/**
	 * 创建SSL安全连接
	 *
	 * @return
	 */
	private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
		SSLConnectionSocketFactory sslsf = null;
		try {
			SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, (chain, authType) -> true).build();
			sslsf = new SSLConnectionSocketFactory(sslContext);
		} catch (GeneralSecurityException e) {
			logger.error(e.getMessage(), e);
		}
		return sslsf;
	}

}
